package satir.analysis.command;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Scanner;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import satir.SatirAnalysis;
import satir.analysis.Analytical;
import satir.analysis.analyst.Factor;
import satir.analysis.analyst.FactorAnalyst;
import satir.framework.InputValidator;
import satir.framework.JSONIOPerformer;
import satir.framework.LazyInitiator;
import satir.framework.JSONIOPerformer.JSONIOPerformerJSONDecodeException;
import satir.framework.JSONIOPerformer.JSONIOPerformerReadException;
import satir.framework.command.RegularCommand;
import satir.framework.command.State;
import satir.framework.graph.Data;
import satir.framework.graph.Generator;
import satir.framework.graph.Person;
import satir.record.Profile;

/**
 * The Class AnalyzeProfileCommand. This Analyze Profile Command is to analyze
 * specific profile
 * @version 3.0 April 2012
 * @author Creative Family
 */
public class AnalyzeProfileCommand implements RegularCommand {

    /** The analyst. */
    SatirAnalysis analyst;

    /**
     * Instantiates a new analyze profile command.
     */
    public AnalyzeProfileCommand() {
    }

    /**
     * Get the profile name in directory.
     */
    public void execute() {
	analyst = SatirAnalysis.instant;
	ArrayList<String> names = analyst.getAllProfileName();
	Scanner scanner = new Scanner(System.in);
	int index = 0;
	boolean invalid;

	// Get the user indication
	do {
	    invalid = false;

	    // Show profile list
	    System.out.println("Please indicate the profile to be analyzed:");
	    int i;
	    for (i = 0; i < names.size(); i++) {
		String name = names.get(i);
		System.out.println("[" + (i + 1) + "] " + name);
	    }
	    i += 1;
	    System.out.println("[" + i + "] Exit");

	    // Retrieve the input
	    String input = scanner.next();
	    if (InputValidator.isInteger(input)) {
		index = Integer.parseInt(input) - 1;
		if (index == i - 1) {
		    return;
		}
		invalid = !InputValidator.isWithinRange(index, 0,
			names.size() - 1);
		if (invalid) {
		    System.out.println("Out Of Range!");
		}
	    } else {
		invalid = true;
		System.out.println("Please input a number");
	    }
	} while (invalid);

	// Analyze
	String name = names.get(index);
	analyzeProfile(analyst.getProfile(name));
    }

    /**
     * Analyze profile.
     * @param profile
     *         the profile
     */
    private void analyzeProfile(final Profile profile) {
	ArrayList<Analytical> analyticals = profile.getAnalyticals();
	Generator generator = new Generator("Analyze", "Analyze on "
		+ profile.getName());
	Person person = new Person(profile.getName());
	Hashtable<String, Integer> values = new Hashtable<String, Integer>();

	// Accumulate all factors
	for (int i = 0; i < analyticals.size(); i++) {
	    Analytical analytical = analyticals.get(i);
	    Hashtable<String, Integer> factors = analytical.getFactors();
	    Enumeration keys = factors.keys();

	    // Accumulate the value for each factor
	    while (keys.hasMoreElements()) {
		String key = (String) keys.nextElement();
		Integer value = factors.get(key);
		if (values.containsKey(key)) {
		    value += values.get(key);
		}
		values.put(key, value);
	    }
	}

	// Select Analyst
	ArrayList<FactorAnalyst> analysts = getFactorAnalyst();

	Scanner scanner = new Scanner(System.in);
	int index = 0;
	boolean invalid;
	do {
	    invalid = false;

	    // Show profile list
	    System.out.println("Please indicate the analyst:");
	    int i;
	    for (i = 0; i < analysts.size(); i++) {
		FactorAnalyst analyst = analysts.get(i);
		System.out.println("[" + (i + 1) + "] " + analyst.getName());
		System.out.println("      - " + analyst.getDescription());
	    }
	    i += 1;
	    System.out.println("[" + i + "] Exit");

	    // Retrieve the input
	    String input = scanner.next();
	    if (InputValidator.isInteger(input)) {
		index = Integer.parseInt(input) - 1;
		if (index == i - 1) {
		    return;
		}
		invalid = !InputValidator.isWithinRange(index, 0, analysts.size() - 1);
		if (invalid) {
		    System.out.println("Out Of Range!");
		}
	    } else {
		invalid = true;
		System.out.println("Please input a number");
	    }
	} while (invalid);

	FactorAnalyst analyst = analysts.get(index);

	// Display result
	System.out.println();
	System.out.println("You have selected '" + analyst.getName()
		+ "' as your analyst.");
	System.out.println("----------Analysis result----------");
	ArrayList<Factor> factors = analyst.getFactors();
	for (int i = 0; i < factors.size(); i++) {
	    Factor factor = factors.get(i);
	    Integer rank = 0;
	    if (values.containsKey(factor.getKey())) {
		rank = values.get(factor.getKey());
	    }
	    System.out.println(factor.getName() + " : "
		    + factor.getInterpretation());
	    System.out.println("Rank : " + rank);
	    System.out.println("Advice : " + factor.getAdvice(rank));

	    // Add data
	    Data data = new Data(factor.getName(), rank);
	    person.addData(data);
	}
	System.out.println("----------Analysis result----------");

	// generate
	generator.addPerson(person);
	generator.generate();
    }

    /**
     * Gets the factor analyst.
     * @return the factor analyst
     */
    private ArrayList<FactorAnalyst> getFactorAnalyst() {
	// Hard code, retrieving data, to be code refectoring
	ArrayList<FactorAnalyst> factorAnalysts = new ArrayList<FactorAnalyst>();
	try {
	    JSONIOPerformer configIO;
	    configIO = new JSONIOPerformer(
		    "config/analysis/analyst/FactorAnalyst.impConfig");
	    JSONObject config = configIO.retrieve();
	    JSONArray analystList = config.getJSONArray("FactorAnalyst");

	    for (int i = 0; i < analystList.length(); i++) {
		JSONObject current = analystList.getJSONObject(i);
		factorAnalysts.add((FactorAnalyst) LazyInitiator.get(
			"FactorAnalyst", current.getString("key")));
	    }

	} catch (JSONIOPerformerReadException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} catch (JSONIOPerformerJSONDecodeException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} catch (JSONException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}
	return factorAnalysts;
    }

    /**
     * Gets the instruction.
     * @return the instruction
     */
    @Override
    public String getInstruction() {
	return "Analyze Specific Profile";
    }

    /**
     * Execute the method.
     * @param state
     *         the State object
     */
    @Override
    public void execute(final State state) {
	execute();
    }
}
